package lobby

import (
	"container/list"
	"time"

	"gddgame.cc/galaxy/utils/def"
)

type Queue struct {
	def.Logger
	Match           Match
	channel         string
	computer        Computer
	Clients         *list.List
	members         map[string]*list.Element
	needRefresh     bool
	successCallback func(users map[string]string, option map[string]interface{})
}

func NewQueue(logger def.Logger, match Match, channel string) *Queue {
	return &Queue{
		Logger:      logger,
		Match:       match,
		channel:     channel,
		computer:    match.GetComputer(channel),
		Clients:     list.New(),
		members:     make(map[string]*list.Element, 15),
		needRefresh: true,
	}
}

func (q *Queue) Push(client *Client) int {
	//fmt.Println("queue push", client)
	element := q.Clients.PushBack(client)
	client.Time = time.Now()
	for userId, _ := range client.Users {
		q.members[userId] = element
	}
	var clients []*Client
	var c map[string]interface{}
	if q.needRefresh {
		clients, c = q.computer.Refresh(q)
	} else {
		clients, c = q.computer.Add(client, q.Clients.Len()-1)
	}

	if clients != nil || len(clients) > 0 {
		goto Computer
	}
	return q.Clients.Len()
Computer:
	users := make(map[string]string)
	for k, _ := range clients {
		for k, v := range clients[k].Users {
			users[k] = v
		}
		q.Pop(clients[k])
	}
	q.successCallback(users, c)
	q.needRefresh = true
	return q.Clients.Len()
}

func (q *Queue) Remove(userId string, all bool) int {
	element, ok := q.members[userId]
	if !ok {
		return q.Clients.Len()
	}
	client := element.Value.(*Client)
	delete(q.members, userId)
	if client.People == 1 || all {
		for k, _ := range client.Users {
			delete(q.members, client.Users[k])
		}
		q.Clients.Remove(element)
	} else {
		delete(client.Users, userId)
		client.People--
	}
	q.needRefresh = true
	return q.Clients.Len()
}

func (q *Queue) Pop(client *Client) int {
	//fmt.Println("queue pop", client)
	userId := ""
	for user, _ := range client.Users {
		userId = user
		break
	}
	element, ok := q.members[userId]
	if !ok {
		return q.Clients.Len()
	}
	for k, _ := range client.Users {
		delete(q.members, client.Users[k])
	}
	q.Clients.Remove(element)
	q.needRefresh = true
	return q.Clients.Len()
}

func (q *Queue) Update() int {
Loop:
	clients, c := q.computer.Timeout()

	if clients != nil || len(clients) > 0 {
		goto Computer
	}
	return q.Clients.Len()
Computer:
	users := make(map[string]string)
	for k, _ := range clients {
		for k, v := range clients[k].Users {
			users[k] = v
		}
		q.Pop(clients[k])
	}
	q.successCallback(users, c)
	q.needRefresh = true
	goto Loop
}

func (q *Queue) Has(userId string) bool {
	_, ok := q.members[userId]
	return ok
}
